/*
 * Copyright (C) 2008 Universidade Federal de Campina Grande
 *  
 * This file is part of OurGrid. 
 *
 * OurGrid is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free 
 * Software Foundation, either version 3 of the License, or (at your option) 
 * any later version. 
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details. 
 * 
 * You should have received a copy of the GNU Lesser General Public License 
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package org.ourgrid.broker.ui.async.gui.graphical.workers;

import java.awt.GridLayout;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;

import org.ourgrid.broker.status.WorkerStatusInfo;
import org.ourgrid.common.interfaces.to.GridProcessHandle;
import org.ourgrid.common.interfaces.to.WorkersPackage;
import org.ourgrid.common.spec.worker.WorkerSpec;

/**
 * This class generate the scheduler worker table.
 */
public class WorkersTable extends AbstractTableModel {

	//TODO It should be a ENUM
	private static final long serialVersionUID = 1L;

	private static final int COLUMN_NUMBER = 0;

	private static final int COLUMN_NAME = 1;

	private static final int COLUMN_SITE = 2;

	private static final int COLUMN_CPU = 3;

	private static final int COLUMN_MEM = 4;

	private static final int COLUMN_TYPE = 5;

	private static final int COLUMN_REPLICA = 6;

	private static final int COLUMN_ANNOTATION = 7;	
	
	private static final int MIN_SIZE = 8;
	

	/** Array of column names */
	//TODO It should be a ENUM
	private String[ ] columnNames = { "#", "Name", "Site", "CPU", "MEM", "Type", "Running", "Annotations" };

	/** Bidimensional Array */
	private BidimensionalArray<String> data;

	/** JTree */
	private final JTable table;

	private int rowCount;


	public WorkersTable() {

		data = new BidimensionalArray<String>( MIN_SIZE );
		table = new JTable( this );
		table.setEnabled( false );
		table.setColumnSelectionAllowed( false );
		table.setCellSelectionEnabled( false );
		table.setRowSelectionAllowed( false );

		rowCount = 0;
	}


	/**
	 * Return JPanel with JScrollPane
	 */
	public JPanel getPanel() {

		JPanel panel = new JPanel();
		panel.setLayout( new GridLayout( 1, 1 ) );

		TableColumn numberColumn = table.getColumnModel().getColumn( 0 );
		numberColumn.setMaxWidth( 30 );
		numberColumn.setMinWidth( 30 ); 
		numberColumn.setPreferredWidth( 30 );

		JScrollPane scroll = new JScrollPane( table );
		panel.add( scroll );
		return panel;
	}


	/**
	 * Repaints and updates the data table
	 */
	private void refreshData() {
		table.repaint();
		super.fireTableDataChanged();
	}


	/**
	 * Refreshes information in data table, reseting the old worker list, and
	 * updating with this new one.
	 */
	private void refreshTable( Map<Integer,HashSet<WorkerStatusInfo>> workers ) {

		data = new BidimensionalArray<String>( MIN_SIZE );

		int i = 0;
		for ( Entry<Integer,HashSet<WorkerStatusInfo>> entry : workers.entrySet() ) {
			for ( WorkerStatusInfo worker : entry.getValue() ) {
				updateTable( worker, i );
				i++;
			}
		}
		rowCount = i;

		refreshData();
		
	}


	private void updateTable( WorkerStatusInfo worker, int workerNumber ) {

		String name = worker.getWorkerSpec().getLocation();
		String site = worker.getWorkerSpec().getAttribute( WorkerSpec.ATT_SITE );
		String cpu = worker.getWorkerSpec().getAttribute( WorkerSpec.ATT_PROCESSOR_FAMILY );
		String mem = worker.getWorkerSpec().getAttribute( WorkerSpec.ATT_MEM );
		String os = worker.getWorkerSpec().getAttribute( WorkerSpec.ATT_OS );
		Map<String, String> annotations = worker.getWorkerSpec().getAnnotations();
		StringBuffer annotationString;

		data.insertAtColumn( COLUMN_NUMBER, workerNumber + "" );

		if ( name != null ) {
			data.insertAtColumn( COLUMN_NAME, name );
		} else {
			data.insertAtColumn( COLUMN_NAME, "?" );
		}

		if ( site != null ) {
			data.insertAtColumn( COLUMN_SITE, site );
		} else {
			data.insertAtColumn( COLUMN_SITE, "?" );
		}

		if ( cpu != null ) {
			data.insertAtColumn( COLUMN_CPU, cpu );
		} else {
			data.insertAtColumn( COLUMN_CPU, "?" );
		}

		if ( mem != null ) {
			data.insertAtColumn( COLUMN_MEM, mem );
		} else { 
			data.insertAtColumn( COLUMN_MEM, "?" );
		}
 
		if ( os != null ) {
			data.insertAtColumn( COLUMN_TYPE, worker.getWorkerSpec().getAttribute( WorkerSpec.ATT_OS ) );
		} else {
			data.insertAtColumn( COLUMN_TYPE, "?" );
		}
		
		if ( annotations != null ) {
			
			annotationString = new StringBuffer();
			
			for(Entry<String,String> tag : annotations.entrySet() ) {
				
				annotationString.append(tag.getKey() + "=" + tag.getValue() + ",");
				
			}
			
			if (annotationString.length() > 0) {
				annotationString.deleteCharAt(annotationString.length()-1);
			}
			
			data.insertAtColumn( COLUMN_ANNOTATION, annotationString.toString() );
			
		} else {
			data.insertAtColumn( COLUMN_ANNOTATION, "?" );
		}

		GridProcessHandle replica = worker.getReplicaHandle();
		if ( replica != null ) {
			data.insertAtColumn( COLUMN_REPLICA, replica.toString() );
		} else {
			data.insertAtColumn( COLUMN_TYPE, "?" );
		}
		
	}


	/** Returns number of columns */
	public int getColumnCount() {

		return columnNames.length;
	}


	/**
	 * @see javax.swing.table.TableModel#getRowCount()
	 */
	public int getRowCount() {

		return rowCount;
	}


	/**
	 * Return object in rowIndex and columnIndex
	 * 
	 * @param rowIndex Row number
	 * @param columnIndex Column number
	 */
	public Object getValueAt( int rowIndex, int columnIndex ) {

		synchronized ( data ) {
			try {
				String value = data.get( rowIndex, columnIndex );
				return value == null ? "" : value;
			} catch ( ArrayIndexOutOfBoundsException e ) {
				return "";
			}
		}
	}


	@Override
	public String getColumnName( int column ) {

		synchronized ( data ) {
			return columnNames[column];
		}
	}


	@Override
	public boolean isCellEditable( int row, int col ) {

		return false;
	}


	public BidimensionalArray<String> getData() {

		return data;
	}


	public JTable getTable() {

		return table;
	}


	public void updateStatus(WorkersPackage workersPackage) {
		this.refreshTable(workersPackage.getWorkersByJob());
	}
}
